package org.quipu.client;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import static com.google.gwt.user.client.ui.HasHorizontalAlignment.ALIGN_CENTER;
import static com.google.gwt.user.client.ui.HasHorizontalAlignment.ALIGN_LEFT;
import static com.google.gwt.user.client.ui.HasHorizontalAlignment.ALIGN_RIGHT;
import static com.google.gwt.user.client.ui.HasVerticalAlignment.ALIGN_MIDDLE;
import static com.google.gwt.user.client.ui.HasVerticalAlignment.ALIGN_TOP;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.datepicker.client.DateBox;
import java.util.LinkedHashMap;
import java.util.Map;
import org.quipu.AppException;
import org.quipu.client.events.AccountChangedEvent;
import org.quipu.client.events.AccountSelectionChangedEvent;
import org.quipu.client.events.AppEvent;
import org.quipu.client.events.AppEventBus;
import org.quipu.client.events.AppEventListener;
import org.quipu.client.events.BookSelectionChangedEvent;
import org.quipu.dto.AccountDto;
import org.quipu.dto.CurrencyDto;
import org.quipu.dto.DebtDto;

public class AccountEditPanel extends AppEventWidget implements AppEventListener {

    private AccountDto editAccount;
    private AccountDto newAccount;
    private final VerticalPanel vPanel;
    private final FlexTable form;
    private final TextBox titleBox;
    private final DateBox dateBox;
    private final CheckBox debtCheckBox;
    private final Button addBalanceBtn;
    private final Button submitBtn;
    private final Button removeBtn;
    private final CurrencyListBox initCurrencyListBox;
    private final TextBox initBalanceTextBox;
    private final Map<Long, Double> initBalances;

    public AccountEditPanel(AppEventBus eventBus, AppCache cache) {
        super(eventBus, cache);

        editAccount = newAccount = new AccountDto();
        initBalances = new LinkedHashMap<Long, Double>();
        vPanel = new VerticalPanel();
        vPanel.addStyleName("controlPanel");
        vPanel.setHorizontalAlignment(ALIGN_LEFT);
        vPanel.setVerticalAlignment(ALIGN_TOP);
        vPanel.setSize("100%", "100%");

        form = new FlexTable();
//        form.setBorderWidth(1);
        vPanel.add(form);

        titleBox = new TextBox();
        titleBox.addStyleName("titleInput");
        dateBox = new DateBox();
        dateBox.addStyleName("dateInput");
        dateBox.setFormat(new DateBox.DefaultFormat(new DateTimeFormat("dd.MM.yyyy")));
        debtCheckBox = new CheckBox();
        debtCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
            @Override
            public void onValueChange(ValueChangeEvent<Boolean> event) {
                repaintForm();
            }
        });
        initCurrencyListBox = new CurrencyListBox(eventBus, cache, null);
        initBalanceTextBox = new TextBox();
        initBalanceTextBox.addStyleName("sumInput");
        addBalanceBtn = new Button("+");
        addBalanceBtn.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                addInitialBallance();
            }
        });
        submitBtn = new Button();
        submitBtn.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                submitAccount();
            }
        });
        removeBtn = new Button("Удалить");
        removeBtn.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                removeAccount();
            }
        });
        setValue(newAccount);
    }

    @Override
    public void init() {
        initCurrencyListBox.init();
        getEventBus().addListener(AccountSelectionChangedEvent.class, this);
        getEventBus().addListener(BookSelectionChangedEvent.class, this);
    }

    public Widget getWidget() {
        return vPanel;
    }

    public void handleEvent(AppEvent event) {
        if(event != null) {
            if(event instanceof AccountSelectionChangedEvent) {
                setValue(((AccountSelectionChangedEvent) event).getObject());
            } else if(event instanceof BookSelectionChangedEvent) {
                if(getCache().getCurrentBook() != null) {
                    newAccount.setBookId(getCache().getCurrentBook().getId());
                    newAccount.clearInitialBallance();
                    setValue(newAccount);
                }
            }
        }
    }

    private void refillForm() {
        titleBox.setValue(editAccount.getTitle());
        dateBox.setValue(editAccount.getCreationDate());
        debtCheckBox.setValue(editAccount.isDebt());
        if(editAccount.isNew()) {
            submitBtn.setText("Создать");
        } else {
            submitBtn.setText("Сохранить");
        }
        initBalances.clear();
        for(Map.Entry<Long, Double> initBalance: editAccount.getInitialBallances().entrySet()) {
            if(initBalance.getValue() != null && initBalance.getValue() > 0) {
                initBalances.put(initBalance.getKey(), initBalance.getValue());
            }
        }
    }

    private void repaintForm() {
        form.removeAllRows();
        int row = 0;
        FlexTable.FlexCellFormatter cellFormatter = form.getFlexCellFormatter();
        form.setWidget(row, 0, new Label("Название счета"));
        cellFormatter.setAlignment(row, 0, ALIGN_RIGHT, ALIGN_MIDDLE);
        form.setWidget(row, 1, titleBox);
        cellFormatter.setAlignment(row, 1, ALIGN_LEFT, ALIGN_MIDDLE);
        cellFormatter.setColSpan(row++, 1, 2);
        form.setWidget(row, 0, new Label("Дата создания"));
        cellFormatter.setAlignment(row, 0, ALIGN_RIGHT, ALIGN_MIDDLE);
        form.setWidget(row, 1, dateBox);
        cellFormatter.setAlignment(row, 1, ALIGN_LEFT, ALIGN_MIDDLE);
        cellFormatter.setColSpan(row++, 1, 2);
        form.setWidget(row, 0, new Label("Контрагент"));
        cellFormatter.setAlignment(row, 0, ALIGN_RIGHT, ALIGN_MIDDLE);
        form.setWidget(row, 1, debtCheckBox);
        debtCheckBox.setEnabled(editAccount.isNew());
        cellFormatter.setAlignment(row, 1, ALIGN_LEFT, ALIGN_MIDDLE);
        cellFormatter.setColSpan(row++, 1, 2);

        if(!debtCheckBox.getValue()) {
            form.setWidget(row, 0, new Label("Начальный баланс"));
            cellFormatter.setAlignment(row, 0, ALIGN_CENTER, ALIGN_MIDDLE);
            cellFormatter.setColSpan(row++, 0, 3);
            form.setWidget(row, 0, initCurrencyListBox.getWidget());
            cellFormatter.setAlignment(row, 0, ALIGN_RIGHT, ALIGN_MIDDLE);
            form.setWidget(row, 1, initBalanceTextBox);
            cellFormatter.setAlignment(row, 1, ALIGN_LEFT, ALIGN_MIDDLE);
            form.setWidget(row, 2, addBalanceBtn);
            cellFormatter.setAlignment(row++, 2, ALIGN_RIGHT, ALIGN_MIDDLE);

            for(Map.Entry<Long, Double> initBalance: initBalances.entrySet()) {
                final CurrencyDto currency = getCache().getCurrency(initBalance.getKey());
                if(currency != null) {
                    form.setWidget(row, 0, new Label(currency.getTitle()));
                    cellFormatter.setAlignment(row, 0, ALIGN_RIGHT, ALIGN_MIDDLE);
                    form.setWidget(row, 1, new Label(StringUtils.formatSum(initBalance.getValue(), true)));
                    Button removeBalanceBtn = new Button("x");
                    removeBalanceBtn.addClickHandler(new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                            removeInitialBalance(currency.getId());
                        }
                    });
                    form.setWidget(row, 2, removeBalanceBtn);
                    cellFormatter.setAlignment(row++, 2, ALIGN_RIGHT, ALIGN_MIDDLE);
                }
            }
        }

        if(!editAccount.isNew()) {
            form.setWidget(row, 0, removeBtn);
            cellFormatter.setAlignment(row, 0, ALIGN_LEFT, ALIGN_MIDDLE);
        }
        form.setWidget(row, 1, submitBtn);
        cellFormatter.setColSpan(row, 1, 2);
        cellFormatter.setAlignment(row, 1, ALIGN_RIGHT, ALIGN_MIDDLE);
    }

    private void setValue(AccountDto account) {
        editAccount = account;
        if(editAccount == null) {
            editAccount = newAccount;
        }
        refillForm();
        repaintForm();
    }

    private void removeAccount() {
        getMainService().removeAccount(editAccount.getId(), new AsyncCallback<Void>() {

            public void onSuccess(Void result) {
                getEventBus().fireEvent(new AccountChangedEvent(AccountEditPanel.this, null));
                setValue(null);
            }

            public void onFailure(Throwable caught) {
                fireError(caught.getMessage());
            }
        });
    }

    private void submitAccount() {
        String errMsg = null;
        final AccountDto account = new AccountDto();
        account.setId(editAccount.getId());
        account.setTitle(titleBox.getText());
        account.setCreationDate(dateBox.getValue());
        account.setBookId(editAccount.getBookId());
        if(debtCheckBox.getValue()) {
            DebtDto debt = new DebtDto();
            debt.setPercent(0.0);
            account.setDebt(debt);
        } else {
            for(Map.Entry<Long, Double> initBalance: initBalances.entrySet()) {
                account.addInitialBallance(initBalance.getKey(), initBalance.getValue());
            }
        }
        if(errMsg == null) {
            getMainService().submitAccount(account, new AsyncCallback<Void>() {

                public void onSuccess(Void result) {
                    getEventBus().fireEvent(new AccountChangedEvent(AccountEditPanel.this, account));
                }

                public void onFailure(Throwable caught) {
                    fireError(caught.getMessage());
                }
            });
        } else {
            Window.alert(errMsg);
        }
    }

    private void addInitialBallance() {
        Long curId = initCurrencyListBox.getValue();
        if(curId != null) {
            if(initBalances.containsKey(curId)) {
                Window.alert("Начальный баланс с такой валютой уже задан");
            } else {
                try {
                    Double balance = StringUtils.parseSum(initBalanceTextBox.getValue());
                    if(balance > 0) {
                        initBalances.put(curId, balance);
                        repaintForm();
                    } else {
                        Window.alert("Начальный баланс должен быть больше 0");
                    }
                } catch(AppException ex) {
                    Window.alert("Неверный формат суммы");
                }
            }
        } else {
            Window.alert("Выберите валюту");
        }
    }

    private void removeInitialBalance(Long currencyId) {
        if(initBalances.remove(currencyId) != null) {
            repaintForm();
        }
    }
}
 